package com.kent.hellokotlin.cClassAndObject

//扩展
/*
Kotlin 能够扩展一个类的新功能而无需继承该类或者使用像装饰者这样的设计模式。 这通过叫做 扩展 的特殊声明完成。
例如，你可以为一个你不能修改的、来自第三方库中的类编写一个新的函数。 这个新增的函数就像那个原始类本来就有的函数一样，
可以用普通的方法调用。 这种机制称为 扩展函数 。此外，也有 扩展属性 ， 允许你为一个已经存在的类添加新的属性。
*/

//扩展函数
/*
声明一个扩展函数，我们需要用一个 接收者类型 也就是被扩展的类型来作为他的前缀。 下面代码为 MutableList<Int> 添加一个swap 函数：
*/
fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
    val tmp = this[index1]
    this[index1] = this[index2]
    this[index2] = tmp
}

//扩展是静态解析的
/*
扩展不能真正的修改他们所扩展的类。通过定义一个扩展，
你并没有在一个类中插入新成员， 仅仅是可以通过该类型的变量用点表达式去调用这个新函数。

我们想强调的是扩展函数是静态分发的，即他们不是根据接收者类型的虚方法。
这意味着调用的扩展函数是由函数调用所在的表达式的类型来决定的， 而不是由表达式运行时求值结果决定的。例如：
*/
fun Shape.getName() = "Shape"

fun Rectangle.getName() = "Rectangle"

fun printClassName(s: Shape) {
    println(s.getName())
}

fun fooExtend() {
    //这个例子会输出 "Shape"，因为调用的扩展函数只取决于参数 s 的声明类型，该类型是 Shape 类。
    printClassName(Rectangle())
}

/*
如果一个类定义有一个成员函数与一个扩展函数，而这两个函数又有相同的接收者类型、 相同的名字，
并且都适用给定的参数，这种情况总是取成员函数。 例如：
*/
private fun foo1() {
    class Example {
        fun printFunctionType() {
            println("Class method")
        }
    }

    fun Example.printFunctionType() {
        println("Extension function")
    }

    Example().printFunctionType()
}

//可空接收者
private fun foo2() {
    /*
    注意可以为可空的接收者类型定义扩展。这样的扩展可以在对象变量上调用， 即使其值为 null，并且可以在函数体内
    检测 this == null，这能让你在没有检测 null 的时候调用 Kotlin 中的toString()：检测发生在扩展函数的内部。
    */
    fun Any?.toString(): String {
        if (this == null) return "null"
        return toString()
    }

    val a: Any? = null
    val b: Any? = Any()
    a.toString()
    b.toString()
}

//扩展属性
/*与函数类似，Kotlin 支持扩展属性：*/
val <T> List<T>.lastIndex: Int
    get() = size - 1

//伴生对象的扩展
private fun fooCompanionExtend() {
    MyClass.printCompanion()
}

class MyClass {
    companion object {}
}

fun MyClass.Companion.printCompanion() {
    println("Companion")
}

//扩展声明为成员
//https://blog.csdn.net/shulianghan/article/details/105275000

fun main() {
    fooCompanionExtend()
}